import { computed, defineComponent, type PropType, ref, shallowRef, toRefs } from "vue";
import { useDocumentEvent, useRender } from "@/framework/vue/hooks";
import type { MenubarItemType, SubItemType, SubMenuDivider, SubMenuItemType } from "./menubar.types.ts";
import "./menubar.less";
import { Divider, Popover } from "ant-design-vue";
import { RightOutlined } from "@ant-design/icons-vue";
import { EventEmitter, mitt } from "@/framework/util/event-emitter.ts";
import { useMitt } from "@/framework/util/events.ts";

type SubItemEventType = {
  "item-close": void;
};

const events = mitt<{
  close: void;
}>();

export default defineComponent({
  name: "menubar",
  props: {
    items: { type: Array as PropType<MenubarItemType[]>, required: true },
  },
  setup(props) {
    const { items } = toRefs(props);

    // 标记任意一个菜单按钮被点击之后，其他菜单可通过hover事件直接展开菜单
    // 当点击菜单按钮或页面其他地方后，取消hover效果
    const hasButtonClicked = ref(false);

    const handleMenuButtonClick = (ev: MouseEvent) => {
      ev.stopPropagation();
      ev.preventDefault();
      hasButtonClicked.value = true;
    };

    useDocumentEvent("click", () => {
      hasButtonClicked.value = false;
    });

    useRender(() => (
      <div class="menubar">
        {items.value.map(it => (
          <MenubarButton key={it.key} item={it} hasButtonClicked={hasButtonClicked.value} onClick={handleMenuButtonClick} />
        ))}
      </div>
    ));

    return {
      hasButtonClicked,
    };
  },
});

const MenubarButton = defineComponent<{
  item: MenubarItemType;
  hasButtonClicked?: boolean;
  onClick?: (ev: MouseEvent) => void;
}>(
  props => {
    const isOpen = ref(false);
    const handleClose = () => (isOpen.value = false);

    const handleMouseOver = () => {
      if (props.hasButtonClicked) {
        events.emit("close");
        isOpen.value = true;
      }
    };

    const subItemsRef = shallowRef<any>();
    useMitt(events, "close", () => {
      handleClose();
      subItemsRef.value?.close?.();
    });

    return () => (
      <Popover
        v-model:open={isOpen.value}
        arrow={false}
        trigger="click"
        placement="bottomLeft"
        v-slots={{
          content: () => !!props.item.children?.length && <MenubarDropdown ref={subItemsRef} items={props.item.children} onClose={handleClose} />,
        }}
        overlayInnerStyle={{ padding: 0 }}
      >
        <div class="menubar-menu-button" onClick={props.onClick} onMouseover={handleMouseOver}>
          <span>{props.item.label}</span>
        </div>
      </Popover>
    );
  },
  { props: ["item", "hasButtonClicked", "onClick"] },
);

const MenubarDropdown = defineComponent<{ items: SubItemType[]; onClose?: () => void }>(
  (props, ctx) => {
    const hasIcon = computed(() => !!props.items.find(it => "icon" in it && !!it.icon));
    const itemsEvents = mitt<SubItemEventType>();

    ctx.expose({
      close: () => {
        itemsEvents.emit("item-close");
      },
    });

    return () => (
      <div class="menubar-dropdown">
        {props.items.map((it, i) => {
          if (isDivider(it)) {
            return <Divider key={it.type + i} style="margin: 5px 0" />;
          }
          return <MenuItem key={it.key} item={it} hasIcon={hasIcon.value} events={itemsEvents} onClose={props.onClose} />;
        })}
      </div>
    );
  },
  { props: ["items", "onClose"] },
);

const MenuItem = defineComponent<{
  item: SubMenuItemType;
  hasIcon: boolean;
  events: EventEmitter<SubItemEventType>;
  onClose?: () => void;
}>(
  props => {
    const isOpen = ref(false);
    const subMenuRef = shallowRef<any>();

    const openSubMenu = () => {
      closeOthers();
      isOpen.value = true;
    };

    const closeSubMenu = () => {
      isOpen.value = false;
    };

    const closeOthers = () => {
      props.events.emit("item-close");
    };

    const handleClick = (ev: MouseEvent) => {
      ev.stopPropagation();
      ev.preventDefault();
      openSubMenu();
    };

    const handleClose = () => {
      isOpen.value = false;
      props.onClose?.();
    };

    useMitt(props.events, "item-close", () => {
      closeSubMenu();
      subMenuRef.value?.close?.();
    });

    return () =>
      !!props.item.children?.length ? (
        <Popover
          key={props.item.key}
          v-model:open={isOpen.value}
          arrow={false}
          trigger="click"
          placement="rightTop"
          v-slots={{ content: () => <MenubarDropdown ref={subMenuRef} items={props.item.children!} onClose={handleClose} /> }}
          overlayInnerStyle={{ padding: 0 }}
          mouseEnterDelay={0.2}
        >
          <MenuItem0 item={props.item} hasIcon={props.hasIcon} isActive={isOpen.value} onClick={handleClick} onMouseover={openSubMenu} />
        </Popover>
      ) : (
        <MenuItem0 item={props.item} hasIcon={props.hasIcon} onClick={handleClose} onMouseover={closeOthers} />
      );
  },
  {
    props: ["item", "hasIcon", "events", "onClose"],
  },
);

function MenuItem0(props: {
  item: SubMenuItemType;
  hasIcon?: boolean;
  isActive?: boolean;
  onClick?: (ev: MouseEvent) => void;
  onMouseover?: (ev: MouseEvent) => void;
}) {
  const it = props.item;

  const handleClick = (ev: MouseEvent) => {
    props.onClick?.(ev);
    props.item.onClick?.();
  };

  return (
    <div class={["menubar-menu-item", props.isActive && "active"]} onClick={handleClick} onMouseover={props.onMouseover}>
      {props.hasIcon ? <span class="menubar-menu-item-icon">{it.icon}</span> : <span></span>}
      <span class="menubar-menu-item-name">{it.label}</span>
      {!!it.extra && <span class="color-text-secondary">{it.extra}</span>}
      {!!it.children?.length && <RightOutlined style="color: var(--color-primary-text)" />}
    </div>
  );
}

const isDivider = (it: SubItemType): it is SubMenuDivider => "type" in it && it.type === "divider";
